package com.qzxy.premiumhotelsystem.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mysql.cj.x.protobuf.Mysqlx;
import com.qzxy.premiumhotelsystem.common.constant.OrderStatusConstant;
import com.qzxy.premiumhotelsystem.common.constant.RoomStatusConstant;
import com.qzxy.premiumhotelsystem.common.result.PageResult;
import com.qzxy.premiumhotelsystem.common.result.Result;
import com.qzxy.premiumhotelsystem.domain.dto.*;
import com.qzxy.premiumhotelsystem.domain.entity.*;
import com.qzxy.premiumhotelsystem.domain.vo.*;
import com.qzxy.premiumhotelsystem.mapper.*;
import com.qzxy.premiumhotelsystem.service.GuestsService;
import com.qzxy.premiumhotelsystem.service.OrdersService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
* @author 14912
* @description 针对表【orders】的数据库操作Service实现
* @createDate 2024-09-12 15:55:14
*/
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders>
    implements OrdersService{

    @Resource
    private OrdersMapper ordersMapper;

    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Resource
    private VipMapper vipMapper;

    @Resource
    private RoomsMapper roomsMapper;

    @Resource
    private GuestsService guestsService;

    @Resource
    private VipTypesMapper vipTypesMapper;

    @Resource
    private RoomTypesMapper roomTypesMapper;


    @Override
    public Result createBookOrder(OrderDTO orderDTO) {
        //TODO 暂时假设从这取，到时候等用户模块完善后看是从这还是redis
        String telephone = (String) StpUtil.getLoginId();
        Guests guests = guestsService.getByTelephone(telephone);
        Integer guestId = guests.getGuestId();
        //要是用户存在未支付的订单，就不能在购买，不管是不是相同类型的
        LambdaQueryWrapper<Orders>  lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Orders::getGuestId,guestId);
        lambdaQueryWrapper.eq(Orders::getStatus,OrderStatusConstant.ORDER_PENDING);
        List<Orders> ordersList = ordersMapper.selectList(lambdaQueryWrapper);
        if (!CollUtil.isEmpty(ordersList)){
            return Result.build(null,500,"当前存在未支付的预订订单，请先去支付");
        }
        //当用户选择会员权益才需要验证
        VipVO vipVO = new VipVO();
        if (orderDTO.getVipTypeId()!= null){
            //这里去查询单个就行了，因为一个用户只能购买一个类型的vip
            vipVO = vipMapper.selectVipVo(guestId,orderDTO.getVipTypeId());
            if (vipVO == null){
                return Result.build(null,500,"vipTypeId存在异常，未找到相关信息");
            }
        }

        //验证房间是否为空闲
        RoomsVO roomsVO = roomsMapper.selectRoomVO(orderDTO.getRoomId());
        if (roomsVO==null){
            return Result.build(null,500,"roomId有误，不存在此房间");
        }
        if (!roomsVO.getStatus().equals(RoomStatusConstant.AVAILABLE)){
            return Result.build(null,500,"来晚了，此房间已被预订");
        }

        Orders orders = new Orders();
        orders.setOrderId(IdUtil.simpleUUID());
        orders.setGuestId(guestId);
        orders.setRoomId(orderDTO.getRoomId());
        orders.setPrice(roomsVO.getPrice());
        orders.setVipTypeId(orderDTO.getVipTypeId());
        orders.setActuallyPrice(ObjectUtil.isEmpty(orderDTO.getVipTypeId()) ? roomsVO.getPrice() : vipVO.getDiscountRate().multiply(roomsVO.getPrice()));
        orders.setStatus(OrderStatusConstant.ORDER_PENDING);
        try {
            Date checkInTime = dateFormat.parse(orderDTO.getCheckInTime());
            orders.setCheckInTime(checkInTime);
            orders.setCheckOutTime(DateUtil.offsetDay(checkInTime,1));
        } catch (ParseException e) {
            throw new RuntimeException("checkInTime日期格式错误，请使用 yyyy-MM-dd HH:mm:ss 格式", e);
        }

        ordersMapper.insert(orders);
        roomsVO.setStatus(RoomStatusConstant.RESERVED);
        int updated = roomsMapper.updateById(BeanUtil.copyProperties(roomsVO, Rooms.class));
        if (updated == 0) {
            return Result.build(null,500,"来晚了，此房间已被预订");
        }

        return Result.ok(orders.getOrderId());

    }

    @Override
    @Transactional
    public Result payBookOrder(PayOrderDTO payOrderDTO) {

        if(!StrUtil.equals("余额支付",payOrderDTO.getPayMethod())){
            // 目前只支持余额支付
            return Result.build(null,500,"抱歉，目前只支持余额支付");
        }

        Orders orders = ordersMapper.selectById(payOrderDTO.getOrderId());
        if (orders == null || !OrderStatusConstant.ORDER_PENDING.equals(orders.getStatus())){
            return Result.build(null,500,"订单不存在或已支付");
        }

        //扣减余额
        guestsService.deductMoney(payOrderDTO.getPayPwd(),orders.getActuallyPrice());

        Date time = new Date(); // 定义当前时间

        //修改订单状态为已支付
        orders.setStatus(OrderStatusConstant.ORDER_PAID);
        orders.setPayTime(time);
        //已设置版本号进行乐观锁判断
        int updated = ordersMapper.updateById(orders);
        if (updated == 0) {
            return Result.build(null,500,"订单支付失败，请重试");
        }
        return Result.ok("订单支付成功，请在规定时间内入住");
    }

    /**
     * 管理端订单分页查询 包含全部
     * @param orderPageDTO
     * @return
     */
    @Override
    public Result<PageResult> pageBookingOrderVos(OrderPageDTO orderPageDTO) {
        IPage<OrderVO> page = new Page<>(orderPageDTO.getPageNo(),orderPageDTO.getPageSize());
        ordersMapper.pageQueryOrderVos(page,orderPageDTO);
        return Result.ok(new PageResult(page.getTotal(),page.getRecords()));
    }

    /**
     * 管理端修改订单信息
     * @param orderUpdateDTO
     * @return
     */
    @Override
    @Transactional
    public Result updateOrderMessage(OrderUpdateDTO orderUpdateDTO) {
        //orderId校验
        Orders orders = ordersMapper.selectById(orderUpdateDTO.getOrderId());
        if (StrUtil.isBlank(orderUpdateDTO.getOrderId())|| orders == null){
            return Result.build(null,500,"你所修改的订单信息不存在，请检查");
        }
        BeanUtil.copyProperties(orderUpdateDTO, orders, CopyOptions.create().setIgnoreNullValue(true));
        Integer oldRoomId = null;
        //roomNumber校验
        if (!StrUtil.isBlank(orderUpdateDTO.getRoomNumber())) {
            LambdaQueryWrapper<Rooms> lqw = new LambdaQueryWrapper<>();
            lqw.eq(Rooms::getRoomNumber, orderUpdateDTO.getRoomNumber());
            Rooms rooms = roomsMapper.selectOne(lqw);
            if (rooms == null) {
                return Result.build(null,500,"房间不存在，请检查");
            }
            oldRoomId = orders.getRoomId();
            orders.setRoomId(rooms.getRoomId());
            //修改新房间的状态为已预订
            LambdaUpdateWrapper<Rooms> luw = new LambdaUpdateWrapper<>();
            luw.eq(Rooms::getRoomId,orders.getRoomId())
                    .set(Rooms::getStatus,RoomStatusConstant.RESERVED);
            roomsMapper.update(luw);
        }

        //由于这里是管理端操作，并发不高，因此可以省去乐观锁(包括订单和房间)
        //如果修改入住时间，对应的退房时间也得改
        if (!StrUtil.isBlank(orderUpdateDTO.getCheckInTime())){
            try {
                Date checkInTime = dateFormat.parse(orderUpdateDTO.getCheckInTime());
//                orders.setCheckInTime(checkInTime);
                orders.setCheckOutTime(DateUtil.offsetDay(checkInTime,1));
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        }
        int updated = ordersMapper.updateById(orders);
        if (updated==0){
            return Result.build(null,500,"订单信息并未变化");
        }
        if (oldRoomId != null){
            orders.setRoomId(oldRoomId);
        }
        //如果是订单取消或者改房间，那么原来的房间就应该还原成空闲
        if (OrderStatusConstant.ORDER_CANCELLED.equals(orderUpdateDTO.getStatus()) || oldRoomId != null){
            LambdaUpdateWrapper<Rooms> luw = new LambdaUpdateWrapper<>();
            luw.eq(Rooms::getRoomId,orders.getRoomId())
                            .set(Rooms::getStatus,RoomStatusConstant.AVAILABLE);
            roomsMapper.update(luw);
        }
        //如果是取消订单，退还余额
        if (OrderStatusConstant.ORDER_CANCELLED.equals(orderUpdateDTO.getStatus())){
            guestsService.repairBalance(orders.getGuestId(),orders.getActuallyPrice());
        }

        return Result.ok("修改订单信息成功");

    }

    @Override
    public Result pageQueryOrders(Integer pageNo, Integer pageSize) {
        //TODO 暂时假设从这取，到时候等用户模块完善后看是从这还是redis
        String telephone = (String) StpUtil.getLoginId();
        Guests guests = guestsService.getByTelephone(telephone);
        Integer guestId = guests.getGuestId();
        IPage<Orders> page = new Page<>(pageNo,pageSize);
        LambdaQueryWrapper<Orders> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Orders::getGuestId,guestId);
        ordersMapper.selectPage(page,lqw);
        return Result.ok(new PageResult(page.getTotal(),page.getRecords()));
    }

    @Override
    public Result selectOrderDetailVO(String orderId) {
        OrderDetailVO orderDetailVO = ordersMapper.selectOrderDetailVO(orderId);
        if (orderDetailVO == null){
            return Result.build(null,500,"您所查询的订单信息不存在");
        }
        Rooms rooms = roomsMapper.selectById(orderDetailVO.getRoomId());
        RoomTypes roomTypes = roomTypesMapper.selectById(rooms.getRoomTypeId());
        RoomsVO roomsVO = RoomsVO.builder().roomId(rooms.getRoomId())
                .roomNumber(rooms.getRoomNumber())
                .roomType(roomTypes.getRoomType())
                .price(roomTypes.getPrice())
                .status(rooms.getStatus())
                .description(rooms.getDescription())
                .roomUrl(roomTypes.getRoomUrl())
                .isAdvice(roomTypes.getIsAdvice())
                .typeExplain(roomTypes.getTypeExplain())
                .build();
        OrderWithRoomVO orderWithRoomVO = BeanUtil.copyProperties(orderDetailVO, OrderWithRoomVO.class);
        orderWithRoomVO.setRoomsVO(roomsVO);

        return Result.ok(orderWithRoomVO);
    }

    @Override
    @Transactional
    public Result cancelOrder(String orderId) {
        Orders ordersDB = ordersMapper.selectById(orderId);

        // 校验订单是否存在
        if (ordersDB == null){
            return Result.build(null,500,"订单不存在");
        }
        String status = ordersDB.getStatus();

        if (!StrUtil.equals(status,OrderStatusConstant.ORDER_PENDING) && !StrUtil.equals(status,OrderStatusConstant.ORDER_PAID) ){
            //只有待支付和已支付状态下用户才能取消订单，不然只能让管理员那边取消
            return Result.build(null,500,"订单状态有误");

        }else {
            if (StrUtil.equals(status,OrderStatusConstant.ORDER_PAID)){
                //退还余额
                //TODO 暂时假设从这取，到时候等用户模块完善后看是从这还是redis
                String telephone = (String) StpUtil.getLoginId();
                Guests guests = guestsService.getByTelephone(telephone);
                Integer guestId = guests.getGuestId();
                guestsService.repairBalance(guestId,ordersDB.getActuallyPrice());

            }
            //更新房间状态
            Rooms rooms = new Rooms();
            rooms.setStatus(RoomStatusConstant.AVAILABLE);
            rooms.setRoomId(ordersDB.getRoomId());
            roomsMapper.updateById(rooms);

            // 更新订单状态
            ordersDB.setStatus(OrderStatusConstant.ORDER_CANCELLED);
            int updated = ordersMapper.updateById(ordersDB);
            if (updated == 0){
                return Result.build(null,500,"系统繁忙，取消订单失败，请稍后重试");
            }
            return Result.ok("取消订单成功");
        }
    }

    @Override
    public Result getOrderDetail(String orderId) {
        OrderDetailVO orderDetailVO = ordersMapper.selectOrderDetailVO(orderId);
        return Result.ok(orderDetailVO);
    }

    @Override
    @Transactional
    public Result reNewOrder(OrderRenewDTO orderRenewDTO) {
        Orders orders = ordersMapper.selectById(orderRenewDTO.getOrderId());
        if (orders == null){
            return Result.build(null,500,"订单不存在");
        }
        if(!StrUtil.equals("余额支付",orderRenewDTO.getPayMethod())){
            // 目前只支持余额支付
            return Result.build(null,500,"抱歉，目前只支持余额支付");
        }
        if (!DateUtil.isIn(new Date(),orders.getCheckInTime(),orders.getCheckOutTime())){
            return Result.build(null,500,"当前时间不允许续订");
        }
        if (!StrUtil.equals(OrderStatusConstant.ORDER_CHECKED_IN,orders.getStatus())){
            return Result.build(null,500,"当前订单状态不允许续订");
        }
        orders.setDurationDay(orders.getDurationDay()+orderRenewDTO.getDurationDay());
        BigDecimal newPrice = orders.getPrice().add(orders.getPrice().multiply(new BigDecimal(orderRenewDTO.getDurationDay())));
        VipTypes vipTypes = vipTypesMapper.selectById(orders.getVipTypeId());
        BigDecimal newActuallyPrice = newPrice.multiply(vipTypes.getDiscountRate());

        //扣减用户余额
        guestsService.deductMoney(orderRenewDTO.getPayPwd(),newActuallyPrice.subtract(orders.getActuallyPrice()));
        orders.setPrice(newPrice);
        orders.setActuallyPrice(newActuallyPrice);
        orders.setCheckOutTime(DateUtil.offsetDay(orders.getCheckOutTime(),orderRenewDTO.getDurationDay()));
        orders.setPayTime(new Date());
        orders.setStatus(OrderStatusConstant.ORDER_EXTENDED);

        int updated = ordersMapper.updateById(orders);
        if (updated == 0) {
            return Result.build(null,500,"续费失败，请重试");
        }
        return Result.ok("续费成功");

    }

    @Override
    public Result findOverdueOrders() {
        List<Orders> ordersList = ordersMapper.findOverdueOrders();
        return Result.ok(ordersList);
    }
}




